package cn.ctvonline.android.kaopu.widget.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

import com.nostra13.universalimageloader.core.assist.ViewScaleType;
import com.nostra13.universalimageloader.core.imageaware.ImageAware;

/**
 * 刚计算完手指间的距离
 * Created by dujian on 15/11/16.
 */
public class ZoomableImageView extends View implements ImageAware {
    private Bitmap bitmap;
    private int width;
    private int height;
    private double lastFingerDis;//屏幕上最后两个手指间的距离
    private float lastMoveX = -1; //最后的点击位置
    private float lastMoveY = -1; //最后的点击位置
    static final int ACTION_INIT_STATUS = 0;
    static final int ACTION_MOVE_STATUS = 1; //移动状态
    static final int ACTION_ZOOM_OUT_STATUS = 2; //缩小状态
    static final int ACTION_ZOOM_IN_STATUS = 3; //放大状态
    private int currentActionStatus; //当前的操作状态(移动，放大，缩小)
    private float moveXDistance, moveYDistance; //x和y方向上的移动距离
    private float totalTranslateX, totalTranslateY;
    private float currentBitmapWidth, currentBitmapHeight;

    /***
     * 记录两根手指间的中心距离
     */
    private float centerPointX, centerPointY;

    static final int ZOOM_IN_RATE_MAX = 4;
    static final int ZOOM_OUT_RATE_MIN = 1;
    /**
     * 记录图片在矩阵上的总缩放比例
     */
    private float totalRatio;

    /**
     * 记录手指移动的距离所造成的缩放比例
     */
    private float scaledRatio;

    /**
     * 记录图片初始化时的缩放比例
     */
    private float initRatio;

    /**
     * bitmap 放大缩小移动的操作矩阵
     */
    private Matrix matrix = new Matrix();

    /**
     * @return
     */
    private OnDoubleClickListener onDoubleClickListener;

    /**
     * 手势识别
     */
    private GestureDetector mGestureDetector;


    public OnDoubleClickListener getOnDoubleClickListener() {
        return onDoubleClickListener;
    }

    public void setOnDoubleClickListener(OnDoubleClickListener onDoubleClickListener) {
        this.onDoubleClickListener = onDoubleClickListener;
    }

    @Override
    public View getWrappedView() {
        return this;
    }

    @Override
    public ViewScaleType getScaleType() {
        return ViewScaleType.FIT_INSIDE;
    }

    @Override
    public boolean isCollected() {
        return false;
    }

    @Override
    public boolean setImageDrawable(Drawable drawable) {
        BitmapDrawable bDrawable = (BitmapDrawable) drawable;
        this.bitmap = bDrawable.getBitmap();
        return true;
    }

    @Override
    public boolean setImageBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
        return true;
    }

    public ZoomableImageView(Context context) {
        super(context);
        currentActionStatus = ACTION_INIT_STATUS;
        mGestureDetector = new GestureDetector(context, new ZoomGestureListener());
    }

    public ZoomableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        currentActionStatus = ACTION_INIT_STATUS;
        mGestureDetector = new GestureDetector(context, new ZoomGestureListener());
    }

    public ZoomableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        currentActionStatus = ACTION_INIT_STATUS;
        mGestureDetector = new GestureDetector(context, new ZoomGestureListener());
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
        //重绘
        invalidate();
    }

    /**
     * 重写onLayout 获取新宽和高
     *
     * @param changed
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) {
            width = getWidth();
            height = getHeight();
        }
    }

    /**
     * 重写onTouchEvent
     * 因为要处理多点触控, 使用getActionMasked代替getAction
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        switch (event.getActionMasked()) {
            //手指按下模式
            case MotionEvent.ACTION_POINTER_DOWN: {
                //两只手指同时按下
                if (event.getPointerCount() == 2) {
                    // 计算两指之间的距离
                    lastFingerDis = measureFingersDistance(event);
                }
            }
            break;
            case MotionEvent.ACTION_MOVE: {
                if (event.getPointerCount() == 1) {
                    doActionMove(event);
                } else if (event.getPointerCount() == 2) {
                    doActionZoom(event);
                }
            }
            break;
            case MotionEvent.ACTION_POINTER_UP: {
                if (event.getPointerCount() == 2) {
                    // 手指离开屏幕时将临时值还原
                    lastMoveX = -1;
                    lastMoveY = -1;
                }
            }
            break;
            case MotionEvent.ACTION_UP: {
                // 手指离开屏幕时将临时值还原
                lastMoveX = -1;
                lastMoveY = -1;
            }
            break;
            default:
                break;
        }
        return true;
    }

    /**
     * 根据currentActionStatus来进行绘制bitmap
     *
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap != null) {
            switch (currentActionStatus) {

                case ACTION_ZOOM_OUT_STATUS:
                case ACTION_ZOOM_IN_STATUS: {
                    drawForZoom(canvas);
                }
                break;
                case ACTION_MOVE_STATUS: {
                    drawForMove(canvas);
                }
                break;
                case ACTION_INIT_STATUS:
                    initBitmap(canvas);
                default:
                    canvas.drawBitmap(bitmap, matrix, null);
                    break;
            }
        }
    }

    private void drawForZoom(Canvas canvas) {
        //重置矩阵
        matrix.reset();
        //进行缩放
        matrix.postScale(totalRatio, totalRatio);
        float scaledWidth = bitmap.getWidth() * totalRatio;
        float scaledHeight = bitmap.getHeight() * totalRatio;
        float translateX = 0f;
        float translateY = 0f;
        //如果当前图片宽度小于屏幕宽度，则按照屏幕中心横坐标进行水平缩放，否则按照两指中心横坐标进行水平缩放
        if (currentBitmapWidth > width) {
            translateX = (width - scaledWidth) / 2;
        } else {
            translateX = totalTranslateX * scaledRatio + centerPointX * (1 - scaledRatio);
            //进行边界检查
            if (translateX > 0) {
                translateX = 0;
            } else if (width - translateX > scaledWidth) {
                translateX = width - scaledWidth;
            }
        }
        // 如果当前图片高度小于屏幕高度，则按屏幕中心的纵坐标进行垂直缩放。否则按两指的中心点的纵坐标进行垂直缩放
        if (currentBitmapHeight < height) {
            translateY = (height - scaledHeight) / 2f;
        } else {
            translateY = totalTranslateY * scaledRatio + centerPointY * (1 - scaledRatio);
            // 进行边界检查，保证图片缩放后在垂直方向上不会偏移出屏幕
            if (translateY > 0) {
                translateY = 0;
            } else if (height - translateY > scaledHeight) {
                translateY = height - scaledHeight;
            }
        }
        // 缩放后对图片进行偏移，以保证缩放后中心点位置不变
        matrix.postTranslate(translateX, translateY);
        totalTranslateX = translateX;
        totalTranslateY = translateY;
        currentBitmapWidth = scaledWidth;
        currentBitmapHeight = scaledHeight;
        canvas.drawBitmap(bitmap, matrix, null);
    }

    private void drawForMove(Canvas canvas) {
        //矩阵重置
        matrix.reset();
        //根据手指移动距离计算移动的偏移量
        float translateX = totalTranslateX + moveXDistance;
        float translateY = totalTranslateY + moveYDistance;
        //按照已有的缩放比例进行缩放
        matrix.postScale(totalRatio, totalRatio);
        //根据偏移量进行移动
        matrix.postTranslate(translateX, translateY);
        totalTranslateX = translateX;
        totalTranslateY = translateY;
        //在画布上绘制bitmap
        canvas.drawBitmap(bitmap, matrix, null);
    }

    private void doActionZoom(MotionEvent event) {
        //区分是放大还是缩小
        calculatePointerCenter(event);
        double fingerDis = measureFingersDistance(event);
        if (fingerDis > lastFingerDis) {
            currentActionStatus = ACTION_ZOOM_IN_STATUS;
        } else {
            currentActionStatus = ACTION_ZOOM_OUT_STATUS;
        }
        //进行缩放检查，放大倍数最大为ZOOM_IN_RATE_MAX，最小倍数为ZOOM_OUT_RATE_MIN
        if ((currentActionStatus == ACTION_ZOOM_IN_STATUS && totalRatio < ZOOM_IN_RATE_MAX * initRatio)
                || (currentActionStatus == ACTION_ZOOM_OUT_STATUS && totalRatio > ZOOM_OUT_RATE_MIN * initRatio)) {
            float scaledRatio = (float) (fingerDis / lastFingerDis);
            totalRatio = totalRatio * scaledRatio;
            if (totalRatio > ZOOM_IN_RATE_MAX * initRatio) {
                totalRatio = ZOOM_IN_RATE_MAX * initRatio;
            } else if (totalRatio < ZOOM_OUT_RATE_MIN * initRatio) {
                totalRatio = ZOOM_OUT_RATE_MIN * initRatio;
            }
            invalidate();
            lastFingerDis = fingerDis;
        }
    }

    private void doActionMove(MotionEvent event) {
        float moveX = event.getX();
        float moveY = event.getY();
        if (lastMoveX == -1 && lastMoveY == -1) {
            lastMoveX = moveX;
            lastMoveY = moveY;
        }
        currentActionStatus = ACTION_MOVE_STATUS;
        moveXDistance = moveX - lastMoveX;
        moveYDistance = moveY - lastMoveY;
        //边界检查，图片禁止出边界
        if (totalTranslateX + moveXDistance > 0) {
            moveXDistance = 0;
        } else if (width - (totalTranslateX + moveXDistance) > currentBitmapWidth) {
            moveXDistance = 0;
        }
        if (totalTranslateY + moveYDistance > 0) {
            moveYDistance = 0;
        } else if (width - (totalTranslateY + moveYDistance) > currentBitmapHeight) {
            moveYDistance = 0;
        }
        invalidate();
        lastMoveX = moveX;
        lastMoveY = moveY;
    }

    /**
     * 计算两个手指之间的距离。
     *
     * @param event
     * @return 两个手指之间的距离
     */
    private double measureFingersDistance(MotionEvent event) {
        if (event.getPointerCount() != 2) {
            return -1;
        } else {
            float disX = Math.abs(event.getX(0) - event.getX(1));
            float disY = Math.abs(event.getY(0) - event.getY(1));
            return Math.sqrt(disX * disX + disY * disY);
        }
    }

    /**
     * 计算两个按压点的中心点位置
     *
     * @param event
     */
    private void calculatePointerCenter(MotionEvent event) {
        float firstX = event.getX(0);
        float firstY = event.getY(0);
        float secondX = event.getX(1);
        float secondY = event.getY(1);
        centerPointX = (firstX + secondX) / 2;
        centerPointY = (firstY + secondY) / 2;
    }

    /**
     * 图片初始化，让图片居中，当图片大小大于屏幕大小时进行适当缩放
     *
     * @param canvas
     */
    private void initBitmap(Canvas canvas) {
        if (bitmap != null) {
            matrix.reset();
            int bitmapWidth = bitmap.getWidth();
            int bitmapHeight = bitmap.getHeight();
            if (bitmapWidth > width || bitmapHeight > height) {
                if (bitmapWidth - width > bitmapHeight - height) {
                    // 当图片宽度大于屏幕宽度时，将图片等比例压缩，使它可以完全显示出来
                    float ratio = width / (bitmapWidth * 1.0f);
                    matrix.postScale(ratio, ratio);
                    float translateY = (height - (bitmapHeight * ratio)) / 2f;
                    //在Y轴上进行移动，保证图片居中显示
                    matrix.postTranslate(0f, translateY);
                    totalTranslateY = translateY;
                    totalRatio = initRatio = ratio;
                } else {
                    // 当图片高度大于屏幕高度时，将图片等比例压缩，使它可以完全显示出来
                    float ratio = height / (bitmapHeight * 1.0f);
                    matrix.postScale(ratio, ratio);
                    float translateX = (width - (bitmapWidth * ratio)) / 2f;
                    // 在横坐标方向上进行偏移，以保证图片居中显示
                    matrix.postTranslate(translateX, 0);
                    totalTranslateX = translateX;
                    totalRatio = initRatio = ratio;
                }
                currentBitmapWidth = bitmapWidth * initRatio;
                currentBitmapHeight = bitmapHeight * initRatio;
            } else {
                // 当图片的宽高都小于屏幕宽高时，直接让图片居中显示
                float translateX = (width - bitmap.getWidth()) / 2f;
                float translateY = (height - bitmap.getHeight()) / 2f;
                matrix.postTranslate(translateX, translateY);
                totalTranslateX = translateX;
                totalTranslateY = translateY;
                totalRatio = initRatio = 1f;
                currentBitmapWidth = bitmapWidth;
                currentBitmapHeight = bitmapHeight;
            }
            canvas.drawBitmap(bitmap, matrix, null);
        }
    }

    class ZoomGestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            if (onDoubleClickListener != null) {
                onDoubleClickListener.onDoubleClick(ZoomableImageView.this);
            }
            return super.onDoubleTap(e);

        }
    }

    public interface OnDoubleClickListener {
        void onDoubleClick(View view);
    }

    //显示最大
    public void zoomToMax() {
        //以屏幕中心横坐标为点
        totalRatio = ZOOM_IN_RATE_MAX * initRatio;
        invalidate();
    }

    public void zoomToMin() {
        totalRatio = ZOOM_OUT_RATE_MIN * initRatio;
        invalidate();
    }
}
